package com.jl.js.core;

import java.nio.ByteBuffer;
import java.util.HashMap;

import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.annotations.JSConstructor;
import org.mozilla.javascript.annotations.JSFunction;
import org.mozilla.javascript.annotations.JSGetter;

public class JSMemoryFile extends ScriptableObject {

	public static HashMap<String, _File> map = new HashMap<String, _File>();

	public JSMemoryFile() {
	}

	private _File f = null;

	@JSConstructor
	public JSMemoryFile(String name) {
		name = name.trim();
		if (map.containsKey(name)) {
			f = map.get(name);
		} else {
			f = new _File(name);
			map.put(name, f);
		}
	}

	@JSFunction
	public void write(ByteArray ba) {
		f.write(ba.getBytes(), 0, ba.length());
	}

	@JSFunction
	public void clear() {
		f.clear();
	}

	@JSFunction
	public byte[] read(int offset, int len) {
		return f.read(offset, len);
	}

	@Override
	@JSGetter
	public int size() {
		return f.size;
	}

	@JSGetter
	public String name() {
		return f.name;
	}

	@Override
	@JSFunction
	public String toString() {
		return "[object MemoryFile]";
	}

	@Override
	public String getClassName() {
		return "MemoryFile";
	}

	private class _File {
		ByteBuffer buffer = null;
		private String name;

		public _File(String name) {
			this.name = name;
			buffer = ByteBuffer.allocate(8);
		}

		volatile int size = 0;
		volatile int current = 0;

		public synchronized void write(byte[] ba, int offset, int len) {
			size += len;
			ensureCapcity();
			buffer.put(ba, offset, len);
			current += len;
		}

		public byte[] read(int offset, int len) {
			if (offset < 0 || offset + len > size) {
				throw new IndexOutOfBoundsException();
			}
			byte[] res = new byte[len];
			for (int i = 0; i < len; i++) {
				res[i] = buffer.get(offset + i);
			}
			return res;
		}

		public void clear() {
			buffer.clear();
			size = 0;
		}

		private void ensureCapcity() {
			if (size > buffer.capacity()) {
				ByteBuffer bb = ByteBuffer.allocate(buffer.capacity() * 2);
				bb.put(read(0, current));
				buffer = bb;
			}
		}
	}

}
